home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / bookmark_previews-0.6.5-fx.xpi / chrome / content / thumbnailview.xml < prev    next >
Text File  |  2008-05-27  |  55KB  |  1,489 lines

  1. <!-- ***** BEGIN LICENSE BLOCK *****
  2.    - Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.    -
  4.    - The contents of this file are subject to the Mozilla Public License Version
  5.    - 1.1 (the "License"); you may not use this file except in compliance with
  6.    - the License. You may obtain a copy of the License at
  7.    - http://www.mozilla.org/MPL/
  8.    -
  9.    - Software distributed under the License is distributed on an "AS IS" basis,
  10.    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.    - for the specific language governing rights and limitations under the
  12.    - License.
  13.    -
  14.    - The Original Code is the Bookmarks Previews extension.
  15.    -
  16.    - The Initial Developer of the Original Code is
  17.    - John Marshall <JohnM555@gmail.com>.
  18.    - Portions created by the Initial Developer are Copyright (C) 2007
  19.    - the Initial Developer. All Rights Reserved.
  20.    -
  21.    - Contributor(s):
  22.    -   John Marshall <JohnM555@gmail.com>
  23.    - Alternatively, the contents of this file may be used under the terms of
  24.    - either the GNU General Public License Version 2 or later (the "GPL"), or
  25.    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26.    - in which case the provisions of the GPL or the LGPL are applicable instead
  27.    - of those above. If you wish to allow use of your version of this file only
  28.    - under the terms of either the GPL or the LGPL, and not to allow others to
  29.    - use your version of this file under the terms of the MPL, indicate your
  30.    - decision by deleting the provisions above and replace them with the notice
  31.    - and other provisions required by the LGPL or the GPL. If you do not delete
  32.    - the provisions above, a recipient may use your version of this file under
  33.    - the terms of any one of the MPL, the GPL or the LGPL.
  34.    -
  35.    - ***** END LICENSE BLOCK ***** -->
  36.  
  37. <bindings xmlns="http://www.mozilla.org/xbl"
  38.           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  39.   <binding id="thumbnailview">
  40.     <content>
  41.       <xul:scrollbox anonid="thumbnailScrollbox"
  42.                      orient="vertical" id="thumbnailView" flex="1"
  43.                      style="overflow: auto; -moz-user-focus: normal;"
  44.                      context="_child">
  45.         <xul:hbox>
  46.           <xul:grid anonid="thumbnailGrid">
  47.  
  48.           </xul:grid>
  49.         </xul:hbox>
  50.         <xul:menupopup id="bookmarksThumbPopup" anonid="bookmarksThumbPopup"
  51.                onpopupshowing="ThumbView.createViewContextMenu(event);"/>
  52.       </xul:scrollbox>
  53.     </content>
  54.     <implementation>
  55.       <method name="superConstructor">
  56.         <parameter name="event"/>
  57.         <body><![CDATA[
  58.           /* Load size from prefs */
  59.           var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  60.                           getService(Components.interfaces.nsIPrefService);
  61.           prefs = prefs.getBranch("extensions.thumbnails.");
  62.           var size = 1;
  63.           if (prefs.prefHasUserValue("size"))
  64.             size = prefs.getIntPref("size");
  65.           var thumbPopup = document.getElementById("thumbsSizePopup");
  66.           thumbPopup.childNodes[size].setAttribute("checked","true");
  67.           this.PREVIEW_WIDTH = this.PREVIEW_SIZES[size];
  68.         ]]></body>
  69.       </method>
  70.  
  71.       <property name="container">
  72.         <getter><![CDATA[
  73.           return document.getAnonymousElementByAttribute(this, "anonid", "thumbnailScrollbox");
  74.         ]]></getter>
  75.       </property>
  76.  
  77.       <!-- ThumbView -->
  78.       <field name="initiated">false</field>
  79.       <field name="PREVIEW_WIDTH">160</field>
  80.       <field name="PREVIEW_SIZES">[80,160,320]</field>
  81.       <field name="NOPREVIEW">"chrome://bookmarkpreviews/skin/nopreview.png"</field>
  82.       <field name="selectedItem">null</field>
  83.       <field name="bookmarks">null</field>
  84.       <field name="maxColCount">null</field>
  85.       <field name="colCount">null</field>
  86.       <field name="rowCount">null</field>
  87.       <field name="rows">null</field>
  88.       <property name="grid">
  89.         <getter><![CDATA[
  90.           return document.getAnonymousElementByAttribute(this,"anonid","thumbnailGrid");
  91.         ]]></getter>
  92.       </property>
  93.       <method name="load">
  94.         <parameter name="images"/>
  95.         <body><![CDATA[
  96.           if (!images) return;
  97.           this.bookmarks = images;
  98.           var thumbDeck = this.parentNode;
  99.           var maxWidth = thumbDeck.boxObject.width;
  100.           var maxHeight = thumbDeck.boxObject.height;
  101.           var colCount = Math.floor(maxWidth / (this.PREVIEW_WIDTH+6));
  102.           if (colCount < 1) colCount = 1;
  103.           this.maxColCount = colCount;
  104.           var rowCount;
  105.           if (colCount > images.length) {
  106.             colCount = images.length;
  107.             rowCount = 1;
  108.           }
  109.           else{
  110.             rowCount = Math.ceil(images.length / colCount);
  111.           }
  112.           this.colCount = colCount;
  113.           this.rowCount = rowCount;
  114.           var grid = this.grid;
  115.           while (grid.lastChild)
  116.             grid.removeChild(grid.lastChild);
  117.  
  118.           var xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  119.           var cols = document.createElement("columns");
  120.           for (var i = 0; i< colCount; i++){
  121.             var col = document.createElement("column");
  122.             cols.appendChild(col);
  123.           }
  124.           grid.appendChild(cols);
  125.  
  126.           var rows = document.createElement("rows");
  127.           for (var rowIndex = 0; rowIndex < rowCount; rowIndex++){
  128.             var row = document.createElement("row");
  129.             for (var colIndex = 0; colIndex < colCount; colIndex++){
  130.               var index = rowIndex * colCount + colIndex;
  131.               if (index >= images.length)
  132.                 break;
  133.               row.appendChild(this._createThumb(images[index]));
  134.             }
  135.             rows.appendChild(row);
  136.           }
  137.           this.rows = rows;
  138.           grid.appendChild(rows);
  139.           if (colIndex>0){
  140.             var ele = rows.firstChild.firstChild;
  141.             this.selectElement(ele);
  142.           } else
  143.             this.selectElement(null);
  144.       ]]></body>
  145.       </method>
  146.  
  147.       <method name="_createThumb">
  148.         <parameter name="item"/>
  149.         <body><![CDATA[
  150.           var xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  151.           var box = document.createElement("vbox");
  152.           box.setAttribute("pack","center");
  153.           box.setAttribute("align","center");
  154.           box.setAttribute("class","thumbnail");
  155.           var imageEle = document.createElement("image");
  156.           //imageEle.setAttribute("src",item.image);
  157.           var img = new Image();
  158.           img.src = item.image;
  159.           imageEle.setAttribute("width",this.PREVIEW_WIDTH);
  160.           if (item.image!=this.NOPREVIEW){
  161.             var self = this;
  162.             function thumb_img_load(){
  163.               imageEle.setAttribute("height",
  164.                   parseInt(img.height * self.PREVIEW_WIDTH / img.width));
  165.               imageEle.setAttribute("maxHeight",imageEle.getAttribute("height"));
  166.               /* re-insert so the row/box will refresh the layout
  167.                 otherwise the height gets stretched/not updated */
  168.               //var nextSibling = imageEle.parentNode.nextSibling;
  169.               //imageEle.parentNode.parentNode.insertBefore(imageEle.parentNode,nextSibling);
  170.               imageEle.setAttribute("src",item.image);
  171.             }
  172.             if (img.complete){
  173.               thumb_img_load();
  174.             }else{
  175.               imageEle.setAttribute("src",this.NOPREVIEW);
  176.               imageEle.setAttribute("height",
  177.                                   200 * this.PREVIEW_WIDTH / 320);
  178.               img.onload = thumb_img_load;
  179.             }
  180.           }
  181.           else{
  182.             imageEle.setAttribute("height",
  183.                                   200 * this.PREVIEW_WIDTH / 320);
  184.             imageEle.setAttribute("src",item.image);
  185.           }
  186.           var desc = document.createElement("label");
  187.           desc.setAttribute("value",item.caption);
  188.           desc.setAttribute("crop","end");
  189.           desc.setAttribute("class","thumbnail-label");
  190.           desc.setAttribute("width",this.PREVIEW_WIDTH);
  191.           desc.setAttribute("maxWidth",this.PREVIEW_WIDTH);
  192.           desc.setAttribute("style","max-width: "+this.PREVIEW_WIDTH+"px;");
  193.  
  194.           var container = document.createElement("vbox");
  195.           container.setAttribute("class","thumbnail-container");
  196.           container.appendChild(imageEle);
  197.           container.appendChild(desc);
  198.  
  199.           var spacer1 = document.createElement("spacer");
  200.           var spacer2 = document.createElement("spacer");
  201.           spacer1.setAttribute("flex","1");
  202.           spacer2.setAttribute("flex","1");
  203.           box.appendChild(spacer1);
  204.           box.appendChild(container);
  205.           box.appendChild(spacer2);
  206.  
  207.           box.setAttribute("tooltiptext",item.caption);
  208.           //box.setAttribute("context","bookmarksThumbPopup");
  209.           imageEle.setAttribute("tooltiptext",item.caption);
  210.           box.setAttribute("ondraggesture","nsDragAndDrop.startDrag(event,ThumbView);");
  211.           return box;
  212.         ]]></body>
  213.       </method>
  214.  
  215.       <method name="updateThumbnail">
  216.         <parameter name="aURL"/>
  217.         <body><![CDATA[
  218.           if (!this.bookmarks) return;
  219.           for (var i = 0; i < this.bookmarks.length; i++){
  220.             if (this.bookmarks[i].url == aURL){
  221.               //dump("found thumbnail match: "+i+"\n");
  222.               var image = this.utils.getImageForURL(aURL);
  223.               this.bookmarks[i].image = image;
  224.               var thumb = this._createThumb(this.bookmarks[i]);
  225.               var toreplace = this.getElementAtIndex(i);
  226.               var isSelected = toreplace.getAttribute("selected");
  227.               toreplace.parentNode.replaceChild(thumb,toreplace);
  228.               if (isSelected == "true"){
  229.                 this.selectedItem = null;
  230.                 this.selectElement(thumb,null);
  231.               }
  232.             }
  233.           }
  234.         ]]></body>
  235.       </method>
  236.  
  237.       <method name="updateNodeTitle">
  238.         <parameter name="aNode"/>
  239.         <parameter name="aPrevValue"/>
  240.         <parameter name="aNewValue"/>
  241.         <body><![CDATA[
  242.           if (!this.bookmarks) return false;
  243.           var index = ThumbView.getIndexOfNode(aNode);
  244.           //dump("update index: "+index+"\n");
  245.           if (index==-1) return false;
  246.           this.bookmarks[index].caption = aNewValue;
  247.           var thumb = this._createThumb(this.bookmarks[index]);
  248.           var toreplace = this.getElementAtIndex(index);
  249.           var isSelected = toreplace.getAttribute("selected");
  250.           toreplace.parentNode.replaceChild(thumb,toreplace);
  251.           if (isSelected == "true"){
  252.             this.selectedItem = null;
  253.             this.selectElement(thumb,null);
  254.           }
  255.           return true;
  256.         ]]></body>
  257.       </method>
  258.  
  259.       <method name="handleKeypress">
  260.         <parameter name="event"/>
  261.         <body><![CDATA[
  262.           //dump("keypress:"+this.selectedItem+"|"+event+"\n");
  263.           var KeyEvent = Components.interfaces.nsIDOMKeyEvent;
  264.           if (!this.selectedItem)
  265.             return;
  266.           try{
  267.           switch(event.keyCode){
  268.             case KeyEvent.DOM_VK_LEFT:
  269.               if (event.altKey){
  270.                 this.utils.back();
  271.                 event.stopPropagation();
  272.                 return;
  273.               }
  274.               var previous = this.selectedItem.previousSibling;
  275.               if (!previous){
  276.                 previous = this.selectedItem.parentNode.lastChild;
  277.               }
  278.               this.selectElement(previous,event);
  279.               event.preventDefault();
  280.               event.stopPropagation();
  281.               break;
  282.             case KeyEvent.DOM_VK_RIGHT:
  283.               if (event.altKey){
  284.                 this.utils.forward();
  285.                 event.preventDefault();
  286.                 event.stopPropagation();
  287.                 return;
  288.               }
  289.               var next = this.selectedItem.nextSibling;
  290.               if (!next){
  291.                 next = this.selectedItem.parentNode.firstChild;
  292.               }
  293.               this.selectElement(next,event);
  294.               event.preventDefault();
  295.               event.stopPropagation();
  296.               break;
  297.             case KeyEvent.DOM_VK_UP:
  298.               var colIdx = this._findElementIndex(this.selectedItem);
  299.               var rowIdx = this._findElementIndex(this.selectedItem.parentNode);
  300.               var newRow = null;
  301.               while (!newRow){
  302.                 rowIdx--;
  303.                 if (rowIdx<0) rowIdx = this.rowCount-1;
  304.                 if ((newRow = this.rows.childNodes[rowIdx]).length>colIdx)
  305.                   newRow = null;
  306.               }
  307.               if (newRow){
  308.                 var next = newRow.childNodes[colIdx];
  309.                 this.selectElement(next,event);
  310.               }
  311.               event.preventDefault();
  312.               event.stopPropagation();
  313.               break;
  314.             case KeyEvent.DOM_VK_DOWN:
  315.               var colIdx = this._findElementIndex(this.selectedItem);
  316.               var rowIdx = this._findElementIndex(this.selectedItem.parentNode);
  317.               var newRow = null;
  318.               while (!newRow){
  319.                 rowIdx++;
  320.                 if (rowIdx==this.rowCount) rowIdx = 0;
  321.                 if ((newRow = this.rows.childNodes[rowIdx]).length>colIdx)
  322.                   newRow = null;
  323.               }
  324.               if (newRow){
  325.                 var next = newRow.childNodes[colIdx];
  326.                 this.selectElement(next,event);
  327.               }
  328.               event.preventDefault();
  329.               event.stopPropagation();
  330.               break;
  331.             case KeyEvent.DOM_VK_RETURN:
  332.             case KeyEvent.DOM_VK_ENTER:
  333.               var tEvt = this.copyEvent(event);
  334.               tEvt.target = tEvt.originalTarget = this.selectedItem;
  335.               tEvt.button = 1;
  336.               this.performAction(tEvt);
  337.               event.preventDefault();
  338.               event.stopPropagation();
  339.               break;
  340.             case KeyEvent.DOM_VK_DELETE:
  341.               var rowIndex = this._findElementIndex(this.selectedItem.parentNode);
  342.               var colIndex = this._findElementIndex(this.selectedItem);
  343.               var index = rowIndex * this.colCount + colIndex;
  344.               ThumbViewUtils.removeItem(this.bookmarks[index]);
  345.               event.preventDefault();
  346.               event.stopPropagation();
  347.               break;
  348.           }
  349.           }catch(e){Components.utils.reportError(e);}
  350.         ]]></body>
  351.       </method>
  352.  
  353.       <!-- called from the thumbnail size menu -->
  354.       <method name="changeSize">
  355.         <parameter name="size"/>
  356.         <body><![CDATA[
  357.           if (this.PREVIEW_WIDTH != this.PREVIEW_SIZES[size]){
  358.             var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  359.                           getService(Components.interfaces.nsIPrefService);
  360.             prefs = prefs.getBranch("extensions.thumbnails.");
  361.             prefs.setIntPref("size",size);
  362.             this.PREVIEW_WIDTH = this.PREVIEW_SIZES[size];
  363.             this.load(this.bookmarks);
  364.           }
  365.         ]]></body>
  366.       </method>
  367.  
  368.       <method name="onResize">
  369.         <parameter name="event"/>
  370.         <body><![CDATA[
  371.           if (this.bookmarks!=null){
  372.             //dump("resize thumb view\n");
  373.             var colCount = Math.floor(this.parentNode.boxObject.width / (this.PREVIEW_WIDTH+6));
  374.             if (colCount != this.maxColCount && colCount > 0)
  375.               this.load(this.bookmarks);
  376.           }
  377.         ]]></body>
  378.       </method>
  379.       <method name="_getClickTarget">
  380.         <parameter name="event"/>
  381.         <body><![CDATA[
  382.           return this._getTargetElement(event.originalTarget);
  383.         ]]></body>
  384.       </method>
  385.       <method name="_getTargetElement">
  386.         <parameter name="target"/>
  387.         <body><![CDATA[
  388.           if (target){
  389.             if (target.className == "thumbnail")
  390.               return target;
  391.             else if (target.tagName == "image")
  392.               return target.parentNode.parentNode;
  393.             else if (target.className == "thumbnail-label")
  394.               return target.parentNode.parentNode;
  395.             else if (target.className == "thumbnail-container")
  396.               return target.parentNode;
  397.           }
  398.           return null;
  399.         ]]></body>
  400.       </method>
  401.       <method name="copyEvent">
  402.         <parameter name="event"/>
  403.         <body><![CDATA[
  404.           var tEvt = {};
  405.           for (var p in event){
  406.             try{
  407.               tEvt[p] = event[p];
  408.             }catch(e){}
  409.           }
  410.           return tEvt;
  411.         ]]></body>
  412.       </method>
  413.  
  414.       <method name="isContainer">
  415.         <parameter name="index"/>
  416.         <body><![CDATA[
  417.           var node = this.nodeForIndex(index);
  418.           return this.nodeIsContainer(node);
  419.         ]]></body>
  420.       </method>
  421.  
  422.       <!-- changed from method to a property -->
  423.       <property name="selectedNode">
  424.         <getter><![CDATA[
  425.           return this.getElementNode(this.selectedItem);
  426.         ]]></getter>
  427.       </property>
  428.  
  429.       <method name="getElementNode">
  430.         <parameter name="target"/>
  431.         <body><![CDATA[
  432.           if (target && target.parentNode){
  433.             var rowIndex = this._findElementIndex(target.parentNode);
  434.             var colIndex = this._findElementIndex(target);
  435.             var index = rowIndex * this.colCount + colIndex;
  436.             return this.nodeForIndex(index);
  437.           }
  438.           return null;
  439.         ]]></body>
  440.       </method>
  441.  
  442.       <method name="nodeForIndex">
  443.         <parameter name="index"/>
  444.         <body><![CDATA[
  445.           if (index>-1 && index<this.bookmarks.length)
  446.               return this.bookmarks[index].node;
  447.           return null;
  448.         ]]></body>
  449.       </method>
  450.  
  451.       <method name="getIndexOfNode">
  452.         <parameter name="aNode"/>
  453.         <body><![CDATA[
  454.           var idx = -1;
  455.           for (var i = 0; i<this.bookmarks.length;i++){
  456.             if (this.bookmarks[i].node.itemId == aNode.itemId){
  457.               idx = i;
  458.               break;
  459.             }
  460.           }
  461.           return idx;
  462.         ]]></body>
  463.       </method>
  464.  
  465.       <method name="selectNode">
  466.         <parameter name="aNode"/>
  467.         <body><![CDATA[
  468.           var idx = this.getIndexOfNode(aNode);
  469.           if (idx == -1) return;
  470.  
  471.           var ele = this.getElementAtIndex(idx);
  472.           this.selectElement(ele);
  473.         ]]></body>
  474.       </method>
  475.  
  476.       <method name="selectElement">
  477.         <parameter name="aTarget"/>
  478.         <parameter name="aEvent"/>
  479.         <body><![CDATA[
  480.           var target = this._getTargetElement(aTarget);
  481.           var xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  482.           if (this.selectedItem!=null){
  483.             this.selectedItem.removeAttribute("selected");
  484.           }
  485.           this.selectedItem = target;
  486.           if (target){
  487.             this.selectedItem.setAttribute("selected","true");
  488.             var nsIScroll = this.container.boxObject.QueryInterface(
  489.                             Components.interfaces.nsIScrollBoxObject);
  490.             nsIScroll.ensureElementIsVisible(this.selectedItem);
  491.             var index = this.getElementIndex(target);
  492.             this.onSelectionChanged(aEvent,index);
  493.             ThumbViewUtils.selectItem(this.bookmarks[index],aEvent);
  494.           }
  495.           else{
  496.             this.onSelectionChanged(aEvent,-1);
  497.             ThumbViewUtils.selectItem(null,aEvent);
  498.           }
  499.         ]]></body>
  500.       </method>
  501.       <method name="_findElementIndex">
  502.         <parameter name="ele"/>
  503.         <body><![CDATA[
  504.           if (ele && ele.parentNode){
  505.             var nodes = ele.parentNode.childNodes;
  506.             for (var i = 0;i<nodes.length;i++){
  507.               if (nodes[i]==ele){
  508.                 return i;
  509.               }
  510.             }
  511.           }
  512.           return -1;
  513.         ]]></body>
  514.       </method>
  515.       <method name="getElementIndex">
  516.         <parameter name="ele"/>
  517.         <body><![CDATA[
  518.           /* ele is one of the thumbnails, ele.parentNode is a row */
  519.           if (ele && ele.parentNode){
  520.             var rowIndex = this._findElementIndex(ele.parentNode);
  521.             var colIndex = this._findElementIndex(ele);
  522.             var index = rowIndex * this.colCount + colIndex;
  523.             return index;
  524.           }
  525.           return -1;
  526.         ]]></body>
  527.       </method>
  528.       <method name="getElementAtIndex">
  529.         <parameter name="index"/>
  530.         <body><![CDATA[
  531.           var rowIndex = Math.ceil((index+1) / this.colCount) - 1;
  532.           if (rowIndex<0) rowIndex = 0;
  533.           var colIndex = index - rowIndex * this.colCount;
  534.           var grid = this.grid;
  535.           var rows = grid.firstChild.nextSibling;
  536.           var ele = rows.childNodes[rowIndex].childNodes[colIndex];
  537.           return ele;
  538.         ]]></body>
  539.       </method>
  540.       <method name="performAction">
  541.         <parameter name="event"/>
  542.         <body><![CDATA[
  543.           if (event.button==2) return;
  544.           var target = this._getClickTarget(event);
  545.           if (target){
  546.             var rowIndex = this._findElementIndex(target.parentNode);
  547.             var colIndex = this._findElementIndex(target);
  548.             var index = rowIndex * this.colCount + colIndex;
  549.  
  550.             ThumbViewUtils.performAction(this.bookmarks[index],event);
  551.           }
  552.         ]]></body>
  553.       </method>
  554.       <method name="setSize">
  555.         <parameter name="ele"/>
  556.         <parameter name="width"/>
  557.         <parameter name="height"/>
  558.         <body><![CDATA[
  559.           var xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  560.           ele.setAttribute("height",height);
  561.           ele.setAttribute("width",width);
  562.           ele.setAttribute("flex", 0);
  563.  
  564.           ele.style.height = height + "px";
  565.           ele.style.minHeight = ele.style.height;
  566.           ele.style.maxHeight = ele.style.height;
  567.  
  568.           ele.style.width = width + "px";
  569.           ele.style.minWidth = ele.style.width;
  570.           ele.style.maxWidth = ele.style.width;
  571.         ]]></body>
  572.       </method>
  573.  
  574.       <!-- nsIPlacesView -->
  575.       <method name="getSelectionNodes">
  576.         <body><![CDATA[
  577.           var node = this.selectedNode;
  578.           if (node)
  579.             return [node];
  580.           return [];
  581.         ]]></body>
  582.       </method>
  583.  
  584.       <!-- nsDragAndDrop -->
  585.       <method name="onDragStart">
  586.         <parameter name="event"/>
  587.         <parameter name="xferData"/>
  588.         <parameter name="dragAction"/>
  589.         <body><![CDATA[
  590.         try{
  591.           //dump("dragstart\n");
  592.           // Drag and Drop does not work while a tree view is sorted.
  593.           //dump("is sorted?: "+this.isSorted+"\n");
  594.           if (this.isSorted)
  595.             throw Components.results.NS_OK;
  596.  
  597.           var nodes = this.getSelectionNodes();
  598.           for (var i = 0; i < nodes.length; ++i) {
  599.             var node = nodes[i];
  600.             //dump("selectionnode["+i+"]: "+node+"\n");
  601.             // Disallow dragging the root node of a tree
  602.             var parent = this._getNodeParent(node);//node.parent;
  603.             //dump("parent: "+parent+"\n");
  604.             if (!parent)
  605.               throw Cr.NS_OK;
  606.  
  607.             // If this node is part of a readonly container (e.g. a livemark) it
  608.             // cannot be moved, only copied, so we must change the action used
  609.             // by the drag session.
  610.             //if (PlacesUtils.nodeIsReadOnly(parent)) {
  611.             if (this.nodeIsReadOnly(parent)){
  612.               dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
  613.               break;
  614.             }
  615.           }
  616.           if (event.ctrlKey)
  617.             dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
  618.           // Stuff the encoded selection into the transferable data object
  619.           xferData.data = this.getTransferData(dragAction);
  620.           //dump("dragstartdone: "+xferData.data+"\n");
  621.           //xferData.data = this._controller.getTransferData(dragAction.action);
  622.         }catch(e){
  623.           //dump("error: "+e+"\nStack: "+e.stack+"\n");
  624.           Components.utils.reportError(e);
  625.         }
  626.         ]]></body>
  627.       </method>
  628.  
  629.       <!-- nsDragAndDrop -->
  630.       <method name="getSupportedFlavours">
  631.         <body><![CDATA[
  632.           //dump("getsupportedflavours\n");
  633.           var flavorSet = new FlavourSet();
  634.           for (var i = 0; i < this.peerDropTypes.length; ++i)
  635.             flavorSet.appendFlavour(this.peerDropTypes[i]);
  636.           return flavorSet;
  637.         ]]></body>
  638.       </method>
  639.  
  640.       <!-- drag & drop -->
  641.       <field name="DROP_BEFORE" readonly="true">-1</field>
  642.       <field name="DROP_ON" readonly="true">0</field>
  643.       <field name="DROP_AFTER" readonly="true">1</field>
  644.       <method name="_getOrientation">
  645.         <parameter name="event"/>
  646.         <parameter name="targetEle"/>
  647.         <parameter name="dragSession"/>
  648.         <body><![CDATA[
  649.           var orientation;
  650.           var source = this._getTargetElement(dragSession.sourceNode);
  651.           if (event.originalTarget.tagName == "row" && targetEle){
  652.             if (event.clientX<targetEle.boxObject.x){
  653.               orientation = this.DROP_BEFORE;
  654.             }
  655.             else if (event.clientX>=targetEle.boxObject.x+targetEle.boxObject.width){
  656.               orienation = this.DROP_AFTER;
  657.             }
  658.             this._lastDND = this.getElementNode(source);
  659.           }
  660.           else{
  661.             var node = targetEle?this.getElementNode(targetEle):null;
  662.             var isContainer = node && this.nodeIsContainer(node);
  663.  
  664.             if (isContainer){
  665.               orientation = this.DROP_ON;
  666.               this._lastDND = this.getElementNode(targetEle);
  667.             } else{
  668.               if (targetEle && targetEle.nextSibling == source){
  669.                 orientation = this.DROP_BEFORE;
  670.               }
  671.               else if (targetEle && targetEle.previousSibling == source){
  672.                 orientation = this.DROP_AFTER;
  673.               }
  674.               else{
  675.                 var mid = targetEle.boxObject.x+targetEle.boxObject.width/2;
  676.                 if (event.clientX<mid)
  677.                   orientation = this.DROP_BEFORE;
  678.                 else
  679.                   orientation = this.DROP_AFTER;
  680.               }
  681.               this._lastDND = this.getElementNode(source);
  682.             }
  683.           }
  684.           return orientation;
  685.         ]]></body>
  686.       </method>
  687.     </implementation>
  688.     <handlers>
  689.       <handler event="dragover"><![CDATA[
  690.         nsDragAndDrop.dragOver(event, this);
  691.       ]]></handler>
  692.       <handler event="dragdrop"><![CDATA[
  693.         nsDragAndDrop.drop(event, this);
  694.       ]]></handler>
  695.       <handler event="keypress"><![CDATA[
  696.         this.handleKeypress(event);
  697.       ]]></handler>
  698.       <handler event="mousedown"><![CDATA[
  699.         var target = this._getClickTarget(event);
  700.         if (!target) return;
  701.         if (event.button == 1){
  702.           /* middle click should open it in tabs */
  703.           this.performAction(event);
  704.         }
  705.         this.selectElement(target,event);
  706.       ]]></handler>
  707.       <handler event="dblclick"><![CDATA[
  708.         this.performAction(event);
  709.       ]]></handler>
  710.     </handlers>
  711.   </binding>
  712.   <binding id="thumbnailview-ff2" extends="chrome://bookmarkpreviews/content/thumbnailview.xml#thumbnailview">
  713.     <implementation>
  714.       <constructor><![CDATA[
  715.         // We implement nsIController
  716.         this.container.controllers.appendController(this.controller);
  717.         this.superConstructor();
  718.        ]]></constructor>
  719.        <destructor><![CDATA[
  720.         //dump("destructor\n");
  721.         this.container.controllers.removeController(this.controller);
  722.         ]]>
  723.       </destructor>
  724.       <property name="utils">
  725.         <getter>return BookmarksPreviewUtils;</getter>
  726.       </property>
  727.  
  728.       <method name="nodeIsReadOnly">
  729.         <parameter name="aNode"/>
  730.         <body><![CDATA[
  731.           return false;
  732.         ]]></body>
  733.       </method>
  734.       <method name="nodeIsContainer">
  735.         <parameter name="aNode"/>
  736.         <body><![CDATA[
  737.           return aNode && RDFCU.IsContainer(BMDS, aNode);
  738.         ]]></body>
  739.       </method>
  740.       <method name="_getNodeParent">
  741.         <parameter name="aResource"/>
  742.         <body><![CDATA[
  743.           return BMDS.getParent(aResource);
  744.         ]]></body>
  745.       </method>
  746.       <method name="getParentResource">
  747.         <parameter name="aResource"/>
  748.         <body><![CDATA[
  749.           return this._getNodeParent(aResource);
  750.         ]]></body>
  751.       </method>
  752.       <property name="currentIndex">
  753.         <getter><![CDATA[
  754.           return this.getElementIndex(this.selectedItem);
  755.         ]]></getter>
  756.       </property>
  757.       <property name="currentResource">
  758.         <getter><![CDATA[
  759.           return this.selectedNode;
  760.         ]]></getter>
  761.       </property>
  762.       <property name="isSorted">
  763.         <getter><![CDATA[
  764.           return ThumbViewUtils.isSorted();
  765.         ]]></getter>
  766.       </property>
  767.       <field name="_selection">null</field>
  768.       <field name="_target">null</field>
  769.  
  770.       <method name="getViewSelection">
  771.         <body><![CDATA[
  772.           var resource = this.selectedNode;
  773.           if (!resource){
  774.             resource = this.utils.displayRoot;
  775.           }
  776.           var parent = BMDS.getParent(resource);
  777.           var selection = BookmarksUtils.getSelectionFromResource(resource, parent);
  778.           //dump("getviewselection: "+selection+"\n");
  779.           return selection;
  780.         ]]></body>
  781.       </method>
  782.  
  783.       <method name="getViewTarget">
  784.         <parameter name="aItem"/>
  785.         <parameter name="aParent"/>
  786.         <parameter name="aOrientation"/>
  787.         <body><![CDATA[
  788.  
  789.           if (!aParent || aParent.Value == "NC:BookmarksTopRoot")
  790.             return BookmarksUtils.getTargetFromFolder(RDF.GetResource("NC:BookmarksRoot"))
  791.  
  792.           if (aOrientation == BookmarksUtils.DROP_ON)
  793.             return BookmarksUtils.getTargetFromFolder(aItem);
  794.  
  795.           RDFC.Init(BMDS, aParent);
  796.           var index = RDFC.IndexOf(aItem);
  797.           if (aOrientation == BookmarksUtils.DROP_AFTER)
  798.             ++index;
  799.           return { parent: aParent, index: index };
  800.         ]]></body>
  801.       </method>
  802.  
  803.       <method name="onSelectionChanged">
  804.         <parameter name="aEvent"/>
  805.         <parameter name="aSelectedIndex"/>
  806.         <body><![CDATA[
  807.           //dump("fftthumbonselectionchanged\n");
  808.           this._selection = this.getViewSelection();
  809.           this._target    = this.getViewTarget(this._selection.item[0], this._selection.parent[0], BookmarksUtils.DROP_BEFORE);
  810.           this.onCommandUpdate();
  811.         ]]></body>
  812.       </method>
  813.  
  814.       # This function saves the current selection state before the tree is rebuilt
  815.       # following a command execution. This allows us to remember which item(s)
  816.       # was/were selected so that the user does not need to constantly refocus the
  817.       # tree to perform a sequence of commands.
  818.       <field name="_savedSelection">null</field>
  819.       <method name="saveSelection">
  820.         <body><![CDATA[
  821.           this._savedSelection = this.selectedNode;
  822.         ]]></body>
  823.       </method>
  824.  
  825.       # This function restores the selection appropriately after a command executes.
  826.       # This is necessary because most commands trigger a rebuild of the tree which
  827.       # destroys the selection. The restoration of selection is handled in three
  828.       # different ways depending on the type of command that has been executed
  829.       <method name="restoreSelection">
  830.         <parameter name="aCommand"/>
  831.         <body><![CDATA[
  832.           this.selectNode(this._savedSelection);
  833.           this._savedSelection = null;
  834.         ]]></body>
  835.       </method>
  836.  
  837.       <method name="createViewContextMenu">
  838.         <parameter name="aEvent"/>
  839.         <body><![CDATA[
  840.         try{
  841.           var selection = this._selection;
  842.           var target    = this._target;
  843.           //dump("createViewContextMenu: "+selection+"|"+target+"\n");
  844.           BookmarksCommand.createContextMenu(aEvent, selection);
  845.           this.onCommandUpdate();
  846.         }catch(e){Components.utils.reportError(e);}
  847.         ]]></body>
  848.       </method>
  849.  
  850.  
  851.       <!-- Drag and drop -->
  852.       <method name="onDrop">
  853.         <parameter name="event"/>
  854.         <parameter name="dropData"/>
  855.         <parameter name="dragSession"/>
  856.         <body><![CDATA[
  857.         try{
  858.           //dump("onDrop\n");
  859.           var selection = BookmarksUtils.getSelectionFromXferData(dragSession);
  860.           var targetEle = this._lastDragTarget;
  861.           if (!targetEle) return;
  862.  
  863.           var rItem = this.getElementNode(targetEle);
  864.           var rParent = BMDS.getParent(rItem);
  865.  
  866.           var orientation = this._getOrientation(event,targetEle,dragSession);
  867.           //dump("orientation: "+orientation+"\n");
  868.           var target = this.getViewTarget(rItem, rParent, orientation);
  869.  
  870.           ThumbViewUtils.updatedSelection = true;
  871.           var checkCopy = dragSession.isDataFlavorSupported("moz/rdfitem");
  872.           const kCopyAction = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
  873.  
  874.           // doCopy defaults to true; check if we should make it false.
  875.           // we make it false only if all the selection items have valid parent
  876.           // bookmark DS containers (i.e. aren't generated via aggregation)
  877.           var doCopy = true;
  878.           if (checkCopy && !(dragSession.dragAction & kCopyAction))
  879.             doCopy = BookmarksUtils.shouldCopySelection("drag", selection);
  880.           try{
  881.             if (doCopy)
  882.               BookmarksUtils.insertAndCheckSelection("drag", selection, target);
  883.             else
  884.               BookmarksUtils.moveAndCheckSelection  ("drag", selection, target);
  885.           }catch(e){
  886.             Components.utils.reportError("ThumbnailError: "+e);
  887.           }
  888.           ThumbViewUtils.updatedSelection = false;
  889.           ThumbViewUtils.refreshDisplay();
  890.           this.selectNode(BookmarksPreviewUtils._lastTransactionItem);
  891.           //setTimeout( function (){ThumbViewUtils.updatedSelection = false},0);
  892.           //dump("ondrop complete\n");
  893.           return;
  894.         }catch(e){Components.utils.reportError(e);}
  895.         ]]></body>
  896.       </method>
  897.       <field name="_lastDragTarget">null</field>
  898.       <!-- nsDragAndDrop -->
  899.       <method name="onDragOver">
  900.         <parameter name="event"/>
  901.         <parameter name="flavor"/>
  902.         <parameter name="session"/>
  903.         <body><![CDATA[
  904.           session.canDrop = true;
  905.         ]]></body>
  906.       </method>
  907.       <method name="canDrop">
  908.         <parameter name="event"/>
  909.         <parameter name="dragSession"/>
  910.         <body><![CDATA[
  911.             //dump("candrop\n");
  912.           var selection = BookmarksUtils.getSelectionFromXferData(dragSession);
  913.           var isBookmark = dragSession.isDataFlavorSupported("moz/rdfitem");
  914.           if (isBookmark && selection.containsImmutable)
  915.             return false;
  916.  
  917.           //TODO actually find the orientation
  918.           var orientation = BookmarksUtils.DROP_ON;
  919.           var targetEle = this._getTargetElement(event.originalTarget);
  920.           //dump("candrop: "+event.target.tagName+"|"+event.originalTarget.tagName+"\n");
  921.           //dump("x: "+event.clientX+"\n");
  922.  
  923.           if (!targetEle && event.originalTarget.tagName!="row")
  924.             return false;
  925.           if (targetEle)
  926.             this._lastDragTarget = targetEle;
  927.  
  928.           if (orientation == BookmarksUtils.DROP_ON)
  929.             return true;
  930.  
  931.           var rsrc = this.mOuter.getRowResource(index);
  932.           var rsrcParent = this.mOuter.getParentResource(index);
  933.  
  934.           var rtype = BookmarksUtils.resolveType(rsrc);
  935.           var rptype = BookmarksUtils.resolveType(rsrcParent);
  936.  
  937.           if (!BookmarksUtils.isValidTargetContainer (rsrcParent, selection))
  938.               return false;
  939.           if (index != 0)
  940.             return true;
  941.           if (rsrc.Value != "NC:BookmarksRoot")
  942.             return true;
  943.           return orientation == BookmarksUtils.DROP_BEFORE ? false : this.mOuter.treeBoxObject.view.isContainerOpen(0)
  944.  
  945.           return true;
  946.         ]]></body>
  947.       </method>
  948.  
  949.       <method name="getTransferData">
  950.         <parameter name="dragAction"/>
  951.         <body><![CDATA[
  952.           try{//var selection = this._selection;
  953.           var resource = this.selectedNode;
  954.           var parent = BMDS.getParent(resource);
  955.           var selection = BookmarksUtils.getSelectionFromResource(resource, parent);
  956.           //dump("getTransferData: "+selection+"\n");
  957.           return BookmarksUtils.getXferDataFromSelection(selection);
  958.           }catch(e){Components.utils.reportError(e);return null;}
  959.         ]]></body>
  960.       </method>
  961.       <field name="peerDropTypes"><![CDATA[
  962.         ["moz/rdfitem",
  963.          "application/x-moz-file",
  964.          "text/x-moz-url",
  965.          "text/unicode"
  966.         ]
  967.       ]]></field>
  968.       <field name="childDropTypes">this.peerDropTypes</field>
  969.  
  970.       <!-- nsIController -->
  971.       <field name="controller" readonly="true"><![CDATA[
  972.       ({
  973.         mOuter: this,
  974.  
  975.         supportsCommand: BookmarksController.supportsCommand,
  976.  
  977.         isCommandEnabled: function (aCommand)
  978.         {
  979.           //dump("ice: "+aCommand+"\n"); return;
  980.           // warning: this is not the called function in BookmarksController.onCommandUpdate
  981.           var selection = this.mOuter._selection;
  982.           var target    = this.mOuter._target;
  983.           return BookmarksController.isCommandEnabled(aCommand, selection, target)
  984.         },
  985.  
  986.         doCommand: function (aCommand)
  987.         {
  988.           //dump("doCOmmand: "+aCommand+"\n");
  989.           var selection = this.mOuter._selection;
  990.           var target    = this.mOuter._target;
  991.           //var selection = ThumbViewUtils._selection;
  992.           //var target = ThumbViewUtils._target;
  993.           //this.mOuter.treeBoxObject.view.selection.selectEventsSuppressed = true;
  994.           //this.mOuter._itemToBeToggled = [];
  995.  
  996.           switch (aCommand) {
  997.           case "cmd_selectAll":
  998.             //this.mOuter.treeBoxObject.view.selection.selectAll();
  999.             break;
  1000.           default:
  1001.             //this.mOuter.saveSelection();
  1002.             BookmarksController.doCommand(aCommand, selection, target);
  1003.             //this.mOuter.restoreSelection(aCommand);
  1004.           }
  1005.           //this.mOuter.treeBoxObject.view.selection.selectEventsSuppressed = false;
  1006.         }
  1007.       })
  1008.       ]]></field>
  1009.       <method name="onCommandUpdate">
  1010.         <body><![CDATA[
  1011.           var selection = this._selection;
  1012.           var target    = this._target;
  1013.           //dump("oncommandupdate: "+selection+"|"+target+"\n");
  1014.           BookmarksController.onCommandUpdate(selection, target);
  1015.         ]]></body>
  1016.       </method>
  1017.     </implementation>
  1018.   </binding>
  1019.   <binding id="thumbnailview-ff3" extends="chrome://bookmarkpreviews/content/thumbnailview.xml#thumbnailview">
  1020.     <implementation>
  1021.       <constructor><![CDATA[
  1022.         this.superConstructor();
  1023.         this.container.setAttribute("context","placesContext");
  1024.        ]]></constructor>
  1025.        <destructor><![CDATA[
  1026.         //dump("destructor\n");
  1027.         ]]>
  1028.       </destructor>
  1029.       <property name="utils">
  1030.         <getter>return PlacesPreviewUtils;</getter>
  1031.       </property>
  1032.       <property name="controller"
  1033.                 readonly="true"
  1034.                 onget="return this._controller;"/>
  1035.  
  1036.       <property name="isSorted">
  1037.         <getter><![CDATA[
  1038.           return this.getResult().sortingMode != Ci.nsINavHistoryQueryOptions.SORT_BY_NONE
  1039.         ]]></getter>
  1040.       </property>
  1041.       <method name="getBestOptions">
  1042.         <body><![CDATA[
  1043.           // Get the best set of grouping options to use, either reuse the
  1044.           // existing ones or create new ones.
  1045.           var options = this.getResult().queryOptions;
  1046.           if (!options)
  1047.             options = PlacesUtils.history.getNewQueryOptions();
  1048.           return options;
  1049.         ]]></body>
  1050.       </method>
  1051.  
  1052.       <method name="nodeIsReadOnly">
  1053.         <parameter name="aNode"/>
  1054.         <body><![CDATA[
  1055.           return PlacesUtils.nodeIsReadOnly(aNode);
  1056.         ]]></body>
  1057.       </method>
  1058.  
  1059.       <method name="nodeIsContainer">
  1060.         <parameter name="aNode"/>
  1061.         <body><![CDATA[
  1062.           return aNode && PlacesUtils.nodeIsContainer(aNode);
  1063.         ]]></body>
  1064.       </method>
  1065.  
  1066.       <method name="createViewContextMenu">
  1067.         <parameter name="aEvent"/>
  1068.         <body><![CDATA[
  1069.         try{
  1070.  
  1071.         }catch(e){Components.utils.reportError(e);}
  1072.         ]]></body>
  1073.       </method>
  1074.       <field name="selType">"single"</field>
  1075.       <method name="onCommandUpdate">
  1076.         <body><![CDATA[
  1077.           //dump("oncommandupdate\n");
  1078.           goUpdatePlacesCommands();
  1079.           goUpdateGlobalEditMenuItems();
  1080.           goUpdateUndoEditMenuItems();
  1081.           goUpdatePasteMenuItems();
  1082.         ]]></body>
  1083.       </method>
  1084.  
  1085.       <method name="buildContextMenu">
  1086.         <parameter name="aPopup"/>
  1087.         <body><![CDATA[
  1088.           //dump("build context menu - thumbnailview: "+aPopup+"\n");
  1089.           this.onCommandUpdate();
  1090.           ThumbViewUtils.updatedSelection = true;
  1091.           var hasChildren =  this.controller.buildContextMenu(aPopup);
  1092.           ThumbViewUtils.updatedSelection = false;
  1093.           return hasChildren;
  1094.         ]]></body>
  1095.       </method>
  1096.  
  1097.       <method name="destroyContextMenu">
  1098.         <parameter name="aPopup"/>
  1099.         <body/>
  1100.       </method>
  1101.  
  1102.       <method name="onSelectionChanged">
  1103.         <parameter name="aEvent"/>
  1104.         <parameter name="aSelectedIndex"/>
  1105.         <body><![CDATA[
  1106.           //dump("Selection changed\n");
  1107.         ]]></body>
  1108.       </method>
  1109.  
  1110.       <property name="showRoot">
  1111.         <getter><![CDATA[
  1112.           return false;
  1113.         ]]></getter>
  1114.       </property>
  1115.  
  1116.       <!-- not really implemented -->
  1117.       <property name="flatList">
  1118.         <getter><![CDATA[
  1119.           return this.getAttribute("flatList") == "true";
  1120.         ]]></getter>
  1121.         <setter><![CDATA[
  1122.           if (this.flatList != val) {
  1123.             this.setAttribute("flatList", val);
  1124.             // reload with the last place set
  1125.             if (this.place)
  1126.               this.place = this.place;
  1127.           }
  1128.           return val;
  1129.         ]]></setter>
  1130.       </property>
  1131.  
  1132.       <field name="_result">null</field>
  1133.       <!-- nsIPlacesView -->
  1134.       <method name="getResult">
  1135.         <body><![CDATA[
  1136.           try {
  1137.             return this._result;
  1138.           }
  1139.           catch (e) {
  1140.             return null;
  1141.           }
  1142.         ]]></body>
  1143.       </method>
  1144.       <!-- nsIPlacesView -->
  1145.       <method name="getResultNode">
  1146.         <body><![CDATA[
  1147.           return this.getResult().root;
  1148.         ]]></body>
  1149.       </method>
  1150.  
  1151.       <field name="view">null</field>
  1152.       <method name="getResultView">
  1153.         <body><![CDATA[
  1154.           try {
  1155.             return this.getResult().viewer;
  1156.           }
  1157.           catch (e) {
  1158.           }
  1159.           return null;
  1160.         ]]></body>
  1161.       </method>
  1162.  
  1163.       <!-- nsIPlacesView -->
  1164.       <property name="place">
  1165.         <getter><![CDATA[
  1166.           return this.getAttribute("place");
  1167.         ]]></getter>
  1168.         <setter><![CDATA[
  1169.           this.setAttribute("place", val);
  1170.           var queriesRef = { };
  1171.           var queryCountRef = { };
  1172.           var optionsRef = { };
  1173.           PlacesUtils.history.queryStringToQueries(val, queriesRef, queryCountRef, optionsRef);
  1174.           if (queryCountRef.value == 0)
  1175.             queriesRef.value = [PlacesUtils.history.getNewQuery()];
  1176.           if (!optionsRef.value)
  1177.             optionsRef.value = PlacesUtils.history.getNewQueryOptions();
  1178.  
  1179.           this.loadQuery(queriesRef.value, optionsRef.value);
  1180.           return val;
  1181.         ]]></setter>
  1182.       </property>
  1183.  
  1184.       <method name="loadQuery">
  1185.         <parameter name="queries"/>
  1186.         <parameter name="options"/>
  1187.         <body><![CDATA[
  1188.           this._result = PlacesUtils.history.executeQueries(queries, queries.length,
  1189.                                                           options);
  1190.           var thumbView = new PlacesThumbView(this.showRoot, this.flatList);
  1191.           //thumbView = new PlacesPreviewTreeView(thumbView, "thumbnail");
  1192.           extendPreviewView(thumbView,"thumbnail");
  1193.           this._result.viewer = thumbView;
  1194.           var bkmks = [];
  1195.           this.utils.getBookmarkImages(bkmks,this.getResultNode());
  1196.           this.load(bkmks);
  1197.           if (!this._controller) {
  1198.             this._controller = new PlacesController(this);
  1199.             this.container.controllers.appendController(this._controller);
  1200.           }
  1201.           this._cachedInsertionPoint = undefined;
  1202.         ]]></body>
  1203.       </method>
  1204.  
  1205.       <!-- nsIPlacesView -->
  1206.       <property name="hasSelection">
  1207.         <getter><![CDATA[
  1208.           return this.selectedItem !=null;
  1209.         ]]></getter>
  1210.       </property>
  1211.  
  1212.       <!-- nsIPlacesView -->
  1213.       <property name="hasSingleSelection">
  1214.         <getter><![CDATA[
  1215.           /* currently only supports single selection */
  1216.           return this.hasSelection;
  1217.         ]]></getter>
  1218.       </property>
  1219.  
  1220.       <!-- nsIPlacesView -->
  1221.       <!-- implemented in the extended thumbnail binding
  1222.         <method name="getSelectionNodes">
  1223.       -->
  1224.  
  1225.       <!-- nsIPlacesView -->
  1226.       <method name="getRemovableSelectionRanges">
  1227.         <body><![CDATA[
  1228.           var node = this.selectedNode;
  1229.           if (node)
  1230.             return [[node]];
  1231.           return [];
  1232.         ]]></body>
  1233.       </method>
  1234.  
  1235.       <!-- nsIPlacesView -->
  1236.       <method name="getCopyableSelection">
  1237.         <body><![CDATA[
  1238.           return this.getSelectionNodes();
  1239.         ]]></body>
  1240.       </method>
  1241.  
  1242.       <!-- nsIPlacesView -->
  1243.       <method name="getDragableSelection">
  1244.         <body><![CDATA[
  1245.           var nodes = this.getSelectionNodes();
  1246.           for (var i = nodes.length - 1; i >= 0; i--) {
  1247.             if (PlacesUtils.nodeIsReadOnly(this._getNodeParent(nodes[i])))
  1248.               nodes.splice(i, 1);
  1249.           }
  1250.           return nodes;
  1251.         ]]></body>
  1252.       </method>
  1253.  
  1254.       <!-- nsIPlacesView -->
  1255.       <!-- implemented in the extended thumbnail component
  1256.         <property name="selectedNode">
  1257.       -->
  1258.  
  1259.       <!-- nsIPlacesView -->
  1260.       <property name="selectedURINode">
  1261.         <getter><![CDATA[
  1262.           var node = this.selectedNode;
  1263.           if (PlacesUtils.nodeIsURI(node))
  1264.             return node;
  1265.           return null;
  1266.         ]]></getter>
  1267.       </property>
  1268.  
  1269.       <!-- nsIPlacesView -->
  1270.       <property name="insertionPoint">
  1271.         <getter><![CDATA[
  1272.           // invalidated on selection and focus changes
  1273.           if (this._cachedInsertionPoint !== undefined)
  1274.             return this._cachedInsertionPoint;
  1275.  
  1276.           // there is no insertion point for history queries
  1277.           // so bail out now and save a lot of work when updating commands
  1278.           var resultNode = this.getResultNode();
  1279.           if (PlacesUtils.nodeIsQuery(resultNode)) {
  1280.             var options = asQuery(resultNode).queryOptions;
  1281.             if (options.queryType == options.QUERY_TYPE_HISTORY)
  1282.               return this._cachedInsertionPoint = null;
  1283.           }
  1284.  
  1285.           var orientation = Ci.nsITreeView.DROP_AFTER;
  1286.  
  1287.           // This is a two-part process. The first part is determining the drop
  1288.           // orientation.
  1289.           // * The default orientation is to drop _after_ the selected item.
  1290.           // * If the selected item is an open container, the default
  1291.           //   orientation is to drop _into_ that container.
  1292.           //
  1293.           // Warning: It may be tempting to use tree indexes in this code, but
  1294.           //          you must not, since the tree is nested and as your tree
  1295.           //          index may change when folders before you are opened and
  1296.           //          closed. You must convert your tree index to a node, and
  1297.           //          then use getIndexOfNode to find your absolute index in
  1298.           //          the parent container instead.
  1299.           //
  1300.           // If the sole selection is an open container, insert into it rather
  1301.           // than adjacent to it. Note that this only applies to _single_
  1302.           // selections - if the last element within a multi-selection is an
  1303.           // open folder, insert _adajacent_ to the selection.
  1304.           //
  1305.           // If the sole selection is the bookmarks toolbar folder, we insert
  1306.           // into it even if it is not opened
  1307.           if (this.hasSingleSelection &&
  1308.               this.nodeIsContainer(this.selectedNode))
  1309.             orientation = Ci.nsITreeView.DROP_ON;
  1310.  
  1311.           this._cachedInsertionPoint =
  1312.             this._getInsertionPoint(this.getElementIndex(this.selectedItem)
  1313.               , orientation);
  1314.           return this._cachedInsertionPoint;
  1315.         ]]></getter>
  1316.       </property>
  1317.  
  1318.       <method name="_disallowInsertion">
  1319.         <parameter name="aContainer"/>
  1320.         <body><![CDATA[
  1321.           // Disallow insertion of items under readonly folders
  1322.           // Disallow insertion of items under the places root
  1323.           return (!PlacesUtils.nodeIsFolder(aContainer) ||
  1324.                    PlacesUtils.nodeIsReadOnly(aContainer) ||
  1325.                    aContainer.itemId == PlacesUtils.placesRootId);
  1326.         ]]></body>
  1327.       </method>
  1328.  
  1329.       <method name="_getInsertionPoint">
  1330.         <parameter name="index"/>
  1331.         <parameter name="orientation"/>
  1332.         <body><![CDATA[
  1333.         //return null; //TODO fix
  1334.           var result = this.getResult();
  1335.           var container = result.root;
  1336.           NS_ASSERT(container, "null container");
  1337.           // When there's no selection, assume the container is the container
  1338.           // the view is populated from (i.e. the result's itemId).
  1339.           if (index != -1) {
  1340.             var lastSelected = this.nodeForIndex(index);
  1341.             if (this.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
  1342.               // If the last selected item is an open container, append _into_
  1343.               // it, rather than insert adjacent to it.
  1344.               container = lastSelected;
  1345.               index = -1;
  1346.             }
  1347.             /* This doesn't apply in the thumbnail view
  1348.             else if (!this._disallowInsertion(lastSelected) &&
  1349.                      lastSelected.containerOpen &&
  1350.                      orientation == Ci.nsITreeView.DROP_AFTER) {
  1351.               // If the last selected item is an open container and the user is
  1352.               // trying to drag into it as a first item, really insert into it.
  1353.               container = lastSelected;
  1354.               orientation = Ci.nsITreeView.DROP_BEFORE;
  1355.               index = 0;
  1356.             }
  1357.             */
  1358.             else {
  1359.               // Use the last-selected node's container unless the root node
  1360.               // is selected, in which case we use the root node itself as the
  1361.               // insertion point.
  1362.               container = this._getNodeParent(lastSelected) || container;
  1363.               // avoid the potentially expensive call to getIndexOfNode()
  1364.               // if we know this container doesn't allow insertion
  1365.               if (this._disallowInsertion(container))
  1366.                 return null;
  1367.               var lsi = PlacesUtils.getIndexOfNode(lastSelected);
  1368.               index = (orientation == Ci.nsITreeView.DROP_BEFORE) ? lsi : lsi + 1;
  1369.             }
  1370.           }
  1371.           if (this._disallowInsertion(container))
  1372.             return null;
  1373.  
  1374.           return new InsertionPoint(container.itemId, index, orientation);
  1375.         ]]></body>
  1376.       </method>
  1377.  
  1378.       <!-- nsIPlacesView -->
  1379.       <field name="peerDropTypes">PlacesUIUtils.GENERIC_VIEW_DROP_TYPES</field>
  1380.  
  1381.       <!-- nsIPlacesView -->
  1382.       <field name="childDropTypes">PlacesUIUtils.GENERIC_VIEW_DROP_TYPES</field>
  1383.  
  1384.       <!-- nsIPlacesView -->
  1385.       <!-- currently only single selection support -->
  1386.       <method name="selectAll">
  1387.         <body><![CDATA[
  1388.           //this.view.selection.selectAll();
  1389.         ]]></body>
  1390.       </method>
  1391.  
  1392.       <method name="_getNodeParent">
  1393.         <parameter name="aNode"/>
  1394.         <body><![CDATA[
  1395.           return aNode.parent;
  1396.         ]]></body>
  1397.       </method>
  1398.       <!-- drag and drop -->
  1399.       <method name="getTransferData">
  1400.         <parameter name="dragAction"/>
  1401.         <body><![CDATA[
  1402.           return this._controller.getTransferData(dragAction.action);
  1403.         ]]></body>
  1404.       </method>
  1405.  
  1406.       <!-- Drag and drop -->
  1407.       <method name="_getSourceView">
  1408.         <parameter name="dragSession"/>
  1409.         <body><![CDATA[
  1410.         var sourceNode = dragSession.sourceNode;
  1411.         /* sourceView doesn't really seem to be used so there
  1412.         is no real point in implementing this. onDrop in the drag
  1413.         helper takes a sourceView as its first argument though.*/
  1414.         return this;
  1415.         ]]></body>
  1416.       </method>
  1417.  
  1418.       <field name="_lastDND">null</field>
  1419.       <!-- Drag and drop -->
  1420.       <method name="onDrop">
  1421.         <parameter name="event"/>
  1422.         <parameter name="dropData"/>
  1423.         <parameter name="dragSession"/>
  1424.         <body><![CDATA[
  1425.         try{
  1426.           var targetEle = this._lastDragTarget;
  1427.           var orientation = this._getOrientation(event,targetEle,dragSession);
  1428.           ThumbViewUtils.updatedSelection = true;
  1429.           var index = this.getElementIndex(this._lastDragTarget);// + orientation;
  1430.           LOG("VOThumb: onDrop: " + index + ", orientation: " + orientation);
  1431.           if (!this.canDrop(event,dragSession))
  1432.             return;
  1433.  
  1434.           // We are responsible for translating the |index| and |orientation|
  1435.           // parameters into a container id and index within the container,
  1436.           // since this information is specific to the view.
  1437.           var ip = this._getInsertionPoint(index, orientation);
  1438.           //dump("ip: "+index+"|"+ip.index+" orient: "+orientation+"\n");
  1439.           if (!ip)
  1440.             throw Cr.NS_ERROR_NOT_AVAILABLE;
  1441.           //var sourceView = this._getSourceView(dragSession);
  1442.           PlacesControllerDragHelper.onDrop(ip);
  1443.           ThumbViewUtils.updatedSelection = false;
  1444.           this.selectNode(this._lastDND);
  1445.           return;
  1446.         }catch(e){Components.utils.reportError(e);}
  1447.         ]]></body>
  1448.       </method>
  1449.       <field name="_lastDragTarget">null</field>
  1450.       <!-- nsDragAndDrop -->
  1451.       <method name="onDragOver">
  1452.         <parameter name="event"/>
  1453.         <parameter name="flavor"/>
  1454.         <parameter name="session"/>
  1455.         <body><![CDATA[
  1456.           session.canDrop = true;
  1457.         ]]></body>
  1458.       </method>
  1459.  
  1460.       <method name="canDrop">
  1461.         <parameter name="event"/>
  1462.         <parameter name="dragSession"/>
  1463.         <body><![CDATA[
  1464.           var result = this.getResult(), node = null;
  1465.           var targetEle = this._getTargetElement(event.originalTarget);
  1466.           if (!targetEle && event.originalTarget.tagName!="row")
  1467.             return false;
  1468.           if (targetEle){
  1469.             this._lastDragTarget = targetEle;
  1470.             node = this.getElementNode(targetEle);
  1471.           }
  1472.           var orientation = this._getOrientation(event,this._lastDragTarget,dragSession);
  1473.           //dump("candrop orientation: "+orientation+"\n");
  1474.           if (orientation == this.DROP_ON) {
  1475.             // The user cannot drop an item into itself or a read-only container
  1476.             var sourceEle = this._getTargetElement(dragSession.sourceNode);
  1477.             if (sourceEle == targetEle || PlacesUtils.nodeIsReadOnly(node))
  1478.               return false;
  1479.           }
  1480.           else if (node && node.parent && PlacesUtils.nodeIsReadOnly(node.parent))
  1481.             return false;
  1482.  
  1483.           return PlacesControllerDragHelper.canDrop(this, orientation);
  1484.         ]]></body>
  1485.       </method>
  1486.     </implementation>
  1487.   </binding>
  1488. </bindings>
  1489.